//065959264	Limor Bagizada	040199770	Sarit Chicotay

import java.io.BufferedWriter;
import java.io.Console;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;

import org.omg.CORBA.DynAnyPackage.InvalidValue;

import Base.Corpus;
import Base.NGram;
import General.DataReader;
import Models.BackOffModel;
import Models.BaseModel;
import Models.HeldOutModel;
import Models.LidstoneModel;


public class Main {

	
	private static String newline = System.getProperty("line.separator");
	private static String tab = "\t";
	
	/**
	 * @param args
	 * @throws IOException 
	 * @throws InvalidValue 
	 */
	public static void main(String[] args) throws IOException {
		
		try
		{
			 // read article's content
			ArrayList<String> content = DataReader.ReadArticles("dataset\\train.txt");
			
			// PrintStatisticalTable_ex2(content);
			
			// create BackOff Model
			PrintStatisticalTable_ex3(content);
			
		}
		catch (Exception e) {
			System.out.println("Error occured: " + e.getMessage());
		}
		
	}
	
	/*
	 * Print statistical results to table.txt
	 */
	private static void PrintStatisticalTable_ex2(ArrayList<String> content) throws Exception
	{
	
		// create lidstone model 
		BaseModel lidstone = new LidstoneModel(content, 1);
		
		// create held-out model
		BaseModel heldout = new HeldOutModel(content, 1);
		
		System.out.println("debugging Lidstone = " + lidstone.debugging());
		System.out.println("debugging HeldOut = " + heldout.debugging());
	
		StringBuilder s = new StringBuilder();
		
		// first line
		Append(s, "065959264");
		Append(s, "Limor Bagizada");
		Append(s, "040199770");
		AppendNewLine(s, "Sarit Chicotay");
		
		// 2nd line
		Append(s, heldout.GetTrainingCorpusSize());
		Append(s, heldout.GetTestCorpusSize()); 
		Append(s, FormatNumber(((LidstoneModel)lidstone).getLambda()));
		AppendNewLine(s, lidstone.GetTrainingCorpusSize());
		
		// table content
		for (int r=0; r<=100; r++)
		{
			// r                   
			Append(s, r);
			
			// f_lambda
			Append(s, FormatNumber((double)lidstone.CalculateProbability(r)*lidstone.GetTrainingCorpusSize()));
			
			// f_HO
			Append(s, FormatNumber((double)heldout.CalculateProbability(r)*heldout.GetTrainingCorpusSize()));
			
			// N_r
		    Append(s, heldout.return_N_r(r));
			
			// t_r
			AppendNewLine(s, ((HeldOutModel)heldout).get_r_counter(r));
		}
		
		// last line - perplexity
		Append(s, "perplexity");
		
		ArrayList<String> testContent = DataReader.ReadArticles("dataset\\test.txt");
		Corpus test = new Corpus(testContent);
		Append(s, FormatNumber(lidstone.get_perplexity(test)));
		Append(s, FormatNumber(heldout.get_perplexity(test)));
		
		Append(s, "0");
		AppendNewLine(s, "0");

	
		// printout data to file
		BufferedWriter out = null;
		try
		{
			// write results to output file
			FileWriter writer = new FileWriter("output\\table.txt");
			out = new BufferedWriter(writer);
			out.write(s.toString());
		}
		finally {
			if (out != null) 
				out.close();
		}
		
	}
	
	/*
	 * Print statistical results
	 */
	private static void PrintStatisticalTable_ex3(ArrayList<String> content) throws Exception
	{
	
		BackOffModel backOff_bigram = new BackOffModel(content);
		
		
		// System.out.println("debugging Back-Off");
		// backOff_bigram.debugging();
		
		// print preplexity on test corpus
		ArrayList<String> testContent = DataReader.ReadArticles("dataset\\test.txt");
		Corpus test = new Corpus(testContent, 2);
		double preplexity = backOff_bigram.get_perplexity(test);
		System.out.println(FormatNumber(preplexity));
		
		PrintStatisticalTable_ex3(backOff_bigram, content, "chair");
		PrintStatisticalTable_ex3(backOff_bigram, content, "bridge");
		PrintStatisticalTable_ex3(backOff_bigram, content, "conscious");
	}
	
	private static void PrintStatisticalTable_ex3(BackOffModel backOff_bigram, ArrayList<String> content, String conditioningWord) throws Exception
	{
	
		StringBuilder s = new StringBuilder();
		
		// first line
		Append(s, "065959264");
		Append(s, "Limor Bagizada");
		Append(s, "040199770");
		AppendNewLine(s, "Sarit Chicotay");
	
		double probability = 0;
		double temp = 0;
		for (String word : backOff_bigram.getUnigramVocubularyKeySet())
		{
			Append(s, word); // x
			temp = backOff_bigram.CalculateProbability(new NGram(word, conditioningWord));
			probability += temp;
			AppendNewLine(s, temp); // p(x|conditioningWord)
		}
		
		temp = backOff_bigram.CalculateProbability(0, conditioningWord);
		probability += temp * backOff_bigram.return_N_r(0); // p(x*|conditioningWord) * N_0
		
		Append(s, backOff_bigram.return_N_r(0)); // N_0
		AppendNewLine(s, temp); // p(x*|conditioningWord)
	
		System.out.println(conditioningWord + ": " + probability);
		
		// printout data to file
		BufferedWriter out = null;
		try
		{
			// write results to output file
			FileWriter writer = new FileWriter("output\\"+conditioningWord+".txt");
			out = new BufferedWriter(writer);
			out.write(s.toString());
		}
		finally {
			if (out != null) 
				out.close();
		}
	}
	
	
	private static void AppendNewLine(StringBuilder s, Object str)
	{
		s.append(str);
		s.append(newline);
	}
	
	private static void Append(StringBuilder s, Object str)
	{
		s.append(str);
		s.append(tab);
	}
	
	private static String FormatNumber(double num)
	{
		float temp;
		String format;
		if (num > 0 && num < 1)
		{
			temp = (float) (Math.round(num * 10000000) / 10000000.0);
			format = "####0.#######";
		}
		else
		{
			temp = (float) (Math.round(num * 100) / 100.0);
			format = "####0.##";
		}
		
		DecimalFormat df = new DecimalFormat(format); 
		String str = df.format(temp);
		return str;
	}
	
}
